package com.roocon.thread.pools;

import java.util.concurrent.*;

public class AdvancedThreadPool {
  private final ThreadPoolExecutor executor;

  public AdvancedThreadPool(int corePoolSize, int maximumPoolSize) {
    this.executor = new ThreadPoolExecutor(
        corePoolSize,
        maximumPoolSize,
        60L,
        TimeUnit.SECONDS,
        new PriorityBlockingQueue<Runnable>(),
        new ThreadPoolExecutor.CallerRunsPolicy()
    );
  }

  public <T> Future<T> submitTask(Callable<T> task, int priority) {
    PriorityRunnable<T> pTask = new PriorityRunnable<>(task, priority);
    return executor.submit(pTask);
  }

  public void shutDown() {
    executor.shutdown();
  }

  public String getStatus() {
    return "Active threads: " + executor.getActiveCount() +
        ", Completed tasks: " + executor.getCompletedTaskCount() +
        ", Total tasks: " + executor.getTaskCount();
  }

  private static class PriorityRunnable<T> implements Runnable, Comparable<PriorityRunnable<T>> {
    private final Callable<T> task;
    private final int priority;

    public PriorityRunnable(Callable<T> task, int priority) {
      this.task = task;
      this.priority = priority;
    }

    @Override
    public void run() {
      try {
        task.call();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }

    @Override
    public int compareTo(PriorityRunnable<T> o) {
      return Integer.compare(o.priority, this.priority); // higher values have higher priority
    }
  }

  public static void main(String[] args) throws InterruptedException {
    AdvancedThreadPool pool = new AdvancedThreadPool(2, 4);

    for (int i = 0; i < 10; i++) {
      int priority = i;
      pool.submitTask(() -> {
        System.out.println("Executing task with priority " + priority + " in thread " + Thread.currentThread().getName());
        Thread.sleep(1000);
        return null;
      }, priority);
    }

    Thread.sleep(5000); // wait for some tasks to complete

    System.out.println(pool.getStatus());

    pool.shutDown();
  }
}
